/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ws.websk.chatEndpoint2;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.websocket.EncodeException;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import ws.websk.chatEndpoint2.messages.Message;
import ws.websk.chatEndpoint2.messages.NicknameMessage;
import ws.websk.chatEndpoint2.messages.ChatMessage;
import ws.websk.chatEndpoint2.messages.PrivateMessage;
import ws.websk.chatEndpoint2.messages.UsersListMessage;

/**
 *
 * @author Jens-Marius Nergård Hansen
 */

@ServerEndpoint(
        value = "/ws2", 
        encoders = {ChatMsgEncoder.class, 
                    NickMsgEncoder.class, 
                    UsersListMsgEncoder.class, 
                    privateMsgEncoder.class},
        decoders = {MsgDecoder.class}
)
public class ChatEndpoint2 {

    // Mapping peers with their username
    private static Map<Session, String> userMap = Collections.synchronizedMap(new HashMap<Session, String>());
    
    @OnMessage
    public void onMessage(Message message, Session session) throws IOException, EncodeException {
        System.out.println("onMessage: " + message + " Num of peers: " + userMap.size());
        if (message instanceof ChatMessage){
            System.out.println("The Message has been recognized as a ChatMessage");
            ChatMessage chatMessage = (ChatMessage) message;
            
            System.out.println("The Session max timeout is: " + session.getMaxIdleTimeout());
            
            chatMessage.setNickname(userMap.get(session));

            //Send the message to all connected clients (excluding the original sender of the message).
            for(Session peer:session.getOpenSessions()){
                if(peer.isOpen() && !peer.equals(session)){
                    peer.getBasicRemote().sendObject(chatMessage); //message will be coded as a JSON String
                }
            }
        } else if(message instanceof NicknameMessage) {
            System.out.println("The Message has been recognized as a NicknameMessage");
            NicknameMessage nicknameMessage = (NicknameMessage) message;
            String nickName = nicknameMessage.getNickname();

            userMap.remove(session);
            while(userMap.containsValue(nickName)) nickName += "I";
            userMap.put(session, nickName);

            //send a message to the client confirming the nickname. (The client will not send any messages unless the nick has been registered.)
            session.getBasicRemote().sendObject(new NicknameMessage(nickName));
            
            //send a list of all current users
            UsersListMessage uLM = new UsersListMessage(new ArrayList(userMap.values()));
            for(Session s:session.getOpenSessions() ){
                    if(s.isOpen()){
                        s.getBasicRemote().sendObject(uLM);
                    }
            }
            
        } else if(message instanceof PrivateMessage) {
            System.out.println("The Message has been recognized as a privateMessage");
            PrivateMessage privateMessage = (PrivateMessage) message;
            
            Session receivingPeer = null;
            for(Entry<Session, String> entry: userMap.entrySet()){
                if(privateMessage.getReceiver().equals(entry.getValue())){
                    receivingPeer = entry.getKey();
                    break;
                }
            }
            if(receivingPeer != null)
                receivingPeer.getBasicRemote().sendObject(privateMessage);
            else
                System.out.println("A private message has been trashed.");           
        }
            
    }

    @OnOpen
    public void onOpen(Session peer){
        System.out.println("Client connected to /ws2: " + peer.getId());
    }

    @OnClose
    public void onClose(Session peer) throws IOException, EncodeException{
        System.out.print("Client disconnected: " + userMap.get(peer));
         
        userMap.remove(peer);
        UsersListMessage uLM = new UsersListMessage(new ArrayList(userMap.values()));
        for(Session s:peer.getOpenSessions() ){
                if(s.isOpen() && !s.equals(peer)){
                    s.getBasicRemote().sendObject(uLM);
                }
        }
    }

    @OnError
    public void onError(Session s, Throwable t) {
    }
}